﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;

namespace Sparklings.Rendering
{
    public class ParticleGenerator
    {
        public Vector2 Position = default(Vector2);
        public int TargetParticleCount
        {
            get { return targetParticleCount; }
            set { targetParticleCount = value; timeSinceLastParticle = 0.0f; }
        }
        public int CurrentParticleCount { get { return particles.Count; } }
        public float ParticleAverageLifespan = 1.5f;
        public Color CurrentlySpawnedColor = Color.White;
        public Texture2D ParticleTexture = null;
        public Texture2D ParticleLightTexture = null;
        public Func<Particle, TimeSpan, Vector2> SpeedUpdaterCalculator = (x, y) => x.Speed;
        public Func<Vector2> InitialSpeedCalculator = GetDefaultInitialSpeedCalculator(0.5f);
        public Func<ParticleGenerator, Vector2> InitialPositionCalculator = (pg) => pg.Position;

        public ParticleGenerator(Level l)
        {
            level = l;
        }
        protected void AddOneParticle()
        {
            particles.Add(new Particle()
            {
                Position = InitialPositionCalculator.Invoke(this),
                Speed = InitialSpeedCalculator.Invoke(),
                Color = CurrentlySpawnedColor,
                TimeLeft = ParticleAverageLifespan - timeSinceLastParticle,
                Lifespan = ParticleAverageLifespan - timeSinceLastParticle
            });
        }
        protected virtual void SpawnMissingSparklings()
        {
            if (TargetParticleCount > particles.Count)
            {
                while (timeSinceLastParticle > ParticleAverageLifespan / TargetParticleCount
                    && TargetParticleCount > particles.Count)
                {
                    timeSinceLastParticle -= ParticleAverageLifespan / TargetParticleCount;
                    AddOneParticle();
                }
            }
        }
        public void Update(GameTime t)
        {
            float elapsed = (float)t.ElapsedGameTime.TotalSeconds;
            foreach (Particle p in particles)
            {
                p.Speed = SpeedUpdaterCalculator.Invoke(p, t.ElapsedGameTime);
                p.Position += p.Speed * elapsed;
                p.TimeLeft -= elapsed;
            }
            timeSinceLastParticle += elapsed;
            particles.RemoveAll(p => p.TimeLeft <= 0);
            SpawnMissingSparklings();
        }
        public void DrawParticles(RenderContext rc)
        {
            if (ParticleTexture == null)
            {
                ParticleTexture = level.ContentManager.Load<Texture2D>("Spark2");
            }
            foreach (Particle p in particles)
            {
                Color c = p.Color;
                float colorScaling = p.TimeLeft / p.Lifespan;
                colorScaling = (float)Math.Sqrt(colorScaling);
                rc.Draw(
                    ParticleTexture,
                    p.Position,
                    new Color(c.ToVector3().X, c.ToVector3().Y, c.ToVector3().Z, colorScaling),
                    0.2f);
            }
        }
        public void DrawLight(RenderContext rc)
        {
            if (ParticleLightTexture != null)
            {
                foreach (Particle p in particles)
                {
                    float colorScaling = p.TimeLeft / p.Lifespan;
                    colorScaling *= colorScaling;
                    //colorScaling = (float)Math.Sqrt((double)colorScaling);
                    Color c = Microsoft.Xna.Framework.Color.FromNonPremultiplied(new Vector4(colorScaling) { W = 1.0f });
                    rc.Draw(ParticleLightTexture, p.Position, c);
                }
            }
        }

        protected float timeSinceLastParticle = 0.0f;
        protected int targetParticleCount = 20;
        protected List<Particle> particles = new List<Particle>();
        protected Level level;
        public static Func<Vector2> GetDefaultInitialSpeedCalculator(float defaultSpeed)
        {
            return () =>
            {
                double rotation = Level.StaticRNG.NextDouble() * Math.PI * 2;
                return new Vector2(
                    (float)(defaultSpeed * Math.Cos(rotation)),
                    (float)(defaultSpeed * Math.Sin(rotation)));
            };
        }
        public class Particle
        {
            public Vector2 Position;
            public Vector2 Speed;
            public float TimeLeft;
            public float Lifespan;
            public Color Color;
        }
    }
}
